//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <crust.h>
#include <svrobj.h>

static  size_t NameHashCode(const wchar_t * pwszName)
{
    unsigned int h = 0;
    const wchar_t *p;

    for (p = pwszName; *p != L'\0'; p++) {
        h += *p;
    }

    return h & (CFG_NAME2NAMEHOOK_HS - 1);
}

DLinkNode  NameHook::s_hash[CFG_NAME2NAMEHOOK_HS];

EXTERN_C DECL_CODEINIT void CDECL InitNameHookHash()
{
    for (int i = 0; i < CFG_NAME2NAMEHOOK_HS; i++) {
        NameHook::s_hash[i].Initialize();
    }
}
#ifdef DEBUG_KMUTEX
KMutex  NameHook::s_nameHookLock(__FILE__, __LINE__);
#else 
KMutex  NameHook::s_nameHookLock;
#endif //DEBUG_KMUTEX

NameHook * NameHook::Create(Object * pObject, CProcess * pProcess, const wchar_t * pwszName)
{
    NameHook * pNameHook;

    pNameHook = (NameHook *) \
        malloc(sizeof(NameHook) + sizeof(wchar_t) * wcslen(pwszName));
    if (!pNameHook) return 0;

    wcscpy(pNameHook->m_wszName, pwszName);
    pNameHook->m_pObject    = pObject;
    pNameHook->m_pProcess   = pProcess;
    s_nameHookLock.Lock();
    s_hash[NameHashCode(pwszName)].InsertLast((DLinkNode *)pNameHook);
    s_nameHookLock.Unlock();

    return pNameHook;
}

NameHook * NameHook::Find(const wchar_t * pwszName)
{
    s_nameHookLock.Lock();
    DLinkNode * pDLinkNode;
    DLinkNode * pHead;
    pHead = &s_hash[NameHashCode(pwszName)];
    pDLinkNode = pHead->Next();

    while (pDLinkNode != pHead) {
        NameHook * pNameHook = (NameHook *)pDLinkNode;
        if (wcscmp(pwszName, pNameHook->m_wszName) == 0) {
            s_nameHookLock.Unlock();
            return pNameHook;
        }
        pDLinkNode = pDLinkNode->Next();
    }

    s_nameHookLock.Unlock();
    return NULL;
}

EXTERN KMutex g_marshalLock;

// Destroy the NameHook and detach  the Object attached on it
//
ECode NameHook::DestroyAndRelease(NameHook * pNameHook)
{
    assert(pNameHook);

    Object * pObject;
    ECode ec = NOERROR;

    s_nameHookLock.Lock();
    pNameHook->Detach();
    s_nameHookLock.Unlock();

    pObject = pNameHook->m_pObject;
    assert(pObject);
    pObject->m_pNameHook = NULL;

    // note: if (CTX_DIFF_PROCESS), we couldn't release stub directly
    //
    if (!pObject->m_pCProcess) {
        // note: no Delete Object and do it in Unregister
        // Do nothing
    }
    else if (pObject->m_pCProcess == GetCurrentProcess()) {
        g_marshalLock.Unlock();
        ec = DetachServer(pObject->m_oid, CTX_SAME_PROCESS);
        g_marshalLock.Lock();
    }
    else {
        g_marshalLock.Unlock();
        ec = DetachServer(pObject->m_oid, CTX_DIFF_PROCESS);
        g_marshalLock.Lock();
    }
    free(pNameHook);

    return ec;
}

// Destroy the NameHook but do not detach  the Object attached on it
//
ECode NameHook::Destroy(NameHook * pNameHook)
{
    assert(pNameHook);

    s_nameHookLock.Lock();
    pNameHook->Detach();
    s_nameHookLock.Unlock();

    free(pNameHook);

    return NOERROR;
}
